import {Timestamp, TS, TSO} from "./Timestamp.ts";
import {parseReplyStatus, type ReplyStatus} from "./ReplyStatus.ts";
import {decode} from "../utils/StrUtils.ts";
import {ANONYMOUS_PREFIX} from "../utils/AnonymousUtils.ts";
import type {ReplyInfoRaw} from "./TopicDetail.ts";
import {type BbsCodeNode, parseContent} from "./BbsCodeNode.ts";
import {calculate} from "../utils/DiceUtils.ts";
import {buildVoteData, type VoteData} from "./Vote.ts";

export interface ReplyInfoSimple {
    authorUid: string | number
    content: string
    replyId: number
    replyToId: number | undefined
    postDatetime: Timestamp | undefined
    title: string | undefined
    topicId: number
    status: ReplyStatus[] | undefined
    anonymous: boolean
    seed: number
    nodes: BbsCodeNode[] | undefined
}

export const buildReplyInfoSimple = (data: any): ReplyInfoSimple => {
    const res = {
        authorUid: data.authorid,
        content: decode(data.content) || "",
        replyId: data.pid,
        replyToId: data.reply_to,
        postDatetime: TSO(data),
        title: data.subject,
        topicId: data.tid,
        status: parseReplyStatus(data.type),
        anonymous: (typeof data.authorid === 'number' && data.authorid < 0) || (typeof data.authorid === 'string' && data.authorid.startsWith(ANONYMOUS_PREFIX)),
        seed: data.tid + data.pid + (typeof data.authorid === 'number' && data.authorid > 0 ? data.authorid : 0),
        nodes: parseContent(data.content)
    };
    calculate(res.nodes, res.seed)
    return res
}

export interface Gift {
    id: number
    count: number
    url: string
}

export const buildGifts = (data: any): Gift[] | undefined => {
    const obj = data[14]
    return obj ? Object.keys(obj).map(key => {
        return {
            id: Number(key),
            count: Number(obj[key]),
            url: `https://img4.nga.178.com/ngabbs/nga_classic/items/5_${key}.png`
        }
    }) : undefined
}

export const buildPunishedUserId = (data: any): number[] | undefined => {
    const obj = data[16]
    return obj ? obj.split(",").map(Number) : undefined
}

export interface Attachment {
    relativePath: string
    parentRelativePath: string
    description: string
    extension: string
    filename: string
    size: number
    type: string
    originalFilename: string
    thumbs: string[]
}

// 原图或默认code
export const attachCode = (uri: string, filename: string) => {
    const type = uri.substring(uri.lastIndexOf('.') + 1)
    switch (type) {
        case "zip" :
            return `[attach]./${uri}?filename=${encodeURI(filename)}[/attach]`
        case "mp3":
        case "mp4" :
            return `[flash]./${uri}[/flash]`
        default :
            return `[img]./${uri}[/img]`
    }
}

export const buildAttachment = (data: any): Attachment => {
    const relativePath = data.url || data.attachurl || "";
    // 混合编码的正确解码方式
    let originalFilename = ""
    try {
        originalFilename = (data.url_utf8_org_name || "")
            .replace(/(%[0-9A-F]{2}){3}/g, (match: string) => decodeURI(match))
            .replace(/%([0-9a-f]){2}/g, (match: string) => String.fromCharCode(parseInt(match.substring(1), 16)))
    } catch (e: any) {
        console.warn('relativePath', relativePath)
        console.warn(e)
        try {
            originalFilename = decodeURI(data.url_utf8_org_name || "")
        } catch (e) {
            console.warn(e)
            originalFilename = data.url_utf8_org_name || ""
        }
    }
    return {
        relativePath: relativePath,
        parentRelativePath: data.path,
        description: data.dscp,
        extension: data.ext,
        filename: data.name,
        size: data.size,
        type: data.type,
        originalFilename,
        thumbs: buildAttachThumbs(relativePath, data.thumb),
    }
}

export const buildAttachThumbs = (relativePath: string, thumb: number): string[] => {
    const thumbEnum = [
        {bit: 8, suffix: ".thumb_ss.jpg"},
        {bit: 16, suffix: ".thumb_s.jpg"},
        {bit: 32, suffix: ".thumb.jpg"},
        {bit: 64, suffix: ".medium.jpg"},
        {bit: 0, suffix: ""},
    ]
    return thumbEnum.filter(({bit}) => (bit & thumb) || bit === 0).map(({suffix}) => relativePath + suffix)
}

export interface ReplyInfo extends ReplyInfoSimple {
    gifts: Gift[] | undefined
    punishedUserId: number[] | undefined
    hotReplies: ReplyInfo[] | undefined
    hotReplyId: number[] | undefined
    comment: ReplyInfo[] | undefined
    commentId: number[] | undefined
    attachments: Attachment[] | undefined
    client: string
    orgForumId: number | undefined
    orgForumName: string | undefined
    agreeCount: number
    disagreeCount: number
    floorNumber: number
    recommendScore: any

    punished?: boolean | undefined
    lastEdit: LastEdit | undefined,
    logs: ReputationLog[] | undefined,
    vote: VoteData | undefined,

    // 是否被屏蔽
    blocked?: boolean | undefined
}

export interface LastEdit {
    timestamp: Timestamp | undefined
    userId: number | undefined
    username: string | undefined
}

export interface ReputationLog {
    type: 'reward' | 'canceled' | 'punishment'
    reputation: number
    prestige: number
    money: number
    reason?: string | undefined
    remark?: string | undefined
    days?: number | undefined
    forumId?: number | undefined
}

export interface AlterInfo {
    lastEdit: LastEdit | undefined,
    logs: ReputationLog[] | undefined,
}

export const buildAlterInfo = (text: string): AlterInfo | undefined => {
    if (!text) return undefined
    let lastEdit: LastEdit | undefined = undefined
    let logs: ReputationLog[] | undefined = undefined

    text.split('\t').filter((i: any) => i)
        .map((i: string) => /\[(.+)]/.exec(i)?.[1])
        .filter((i: any) => i)
        .map((i: any) => {
            const type = i[0]
            const data = i.substring(1).split(' ')
            return {type, data}
        })
        .forEach(({type, data}) => {
            switch (type) {
                case 'E': {
                    lastEdit = {
                        timestamp: TS(Number(data[0])),
                        userId: data[1] ? Number(data[1]) : undefined,
                        username: data[2],
                    }
                    break
                }
                case 'L': {
                    logs = logs || []
                    logs.push({
                        type: "punishment",
                        reputation: Number(data[3]),
                        prestige: Number(data[4]),
                        money: Number(data[2]) * 10000,
                        forumId: Number(data[1]),
                        days: Number(data[0]),
                        reason: data[5],
                    })
                    break
                }
                case 'U': {
                    logs = logs || []
                    logs.push({
                        type: "canceled",
                        reputation: Number(data[0]),
                        prestige: Number(data[1]),
                        money: Number(data[2]) * 10000,
                        remark: data[3],
                    })
                    break
                }
                case 'A': {
                    logs = logs || []
                    logs.push({
                        type: "reward",
                        reputation: Number(data[0]),
                        prestige: Number(data[1]) * 10,
                        money: Number(data[2]) * 10000,
                        reason: data[4],
                    })
                    break
                }

            }
        })
    // console.log({lastEdit, logs})
    return {lastEdit, logs}
}

export const buildReplyInfo = (data: ReplyInfoRaw): ReplyInfo => {
    const simple = buildReplyInfoSimple(data);

    const {lastEdit, logs} = buildAlterInfo(data.alterinfo) || {};

    return {
        ...simple, lastEdit, logs,
        gifts: buildGifts(data),
        punishedUserId: buildPunishedUserId(data),
        hotReplies: data.hotreply ? data.hotreply.map((item: any) => buildReplyInfo(item)) : undefined,
        hotReplyId: data.hotreply_id?.filter((i: any) => i).map(Number),
        comment: data.comment ? data.comment.map((item: any) => buildReplyInfo(item)) : undefined,
        commentId: data.comment_id?.filter((i: any) => i).map(Number),
        attachments: data.attachs ? Object.values(data.attachs).map(buildAttachment) : undefined,
        client: data.from_client,
        orgForumId: data.org_fid,
        orgForumName: data.js_escap_org_forum,
        agreeCount: data.score,
        disagreeCount: data.score_2,
        recommendScore: data.recommend,
        floorNumber: data.lou,
        vote: buildVoteData(data.vote)
    }
}